package org.xhy.sniffer.plugin;

import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.matcher.ElementMatcher;
import org.xhy.sniffer.interceptor.ConstructorMethodsInterceptorPoint;
import org.xhy.sniffer.interceptor.InstanceMethodsInterceptorPoint;
import org.xhy.sniffer.interceptor.StaticMethodsInterceptorPoint;
import org.xhy.sniffer.interceptor.enhance.ConstructorInter;
import org.xhy.sniffer.interceptor.enhance.InstMethodsInter;
import org.xhy.sniffer.interceptor.enhance.StaticMethodsInter;

import static net.bytebuddy.matcher.ElementMatchers.*;

/**
 * @description: 封装增强逻辑
 * @gitee: https://gitee.com/XhyQAQ
 * @copyright: B站: https://space.bilibili.com/152686439
 * @Author: Xhy
 * @CreateTime: 2024-07-11 19:46
 */
@Slf4j
public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePluginDefine{


    // 构建方法增强逻辑
    @Override
    protected DynamicType.Builder<?> enhanceMethod(TypeDescription typeDescription, DynamicType.Builder<?> builder, ClassLoader classLoader) {

        final InstanceMethodsInterceptorPoint[] instanceMethodsInterceptorPoints =
                getInstanceMethodsInterceptorPoints();
        final String typeName = typeDescription.getTypeName();


        final ConstructorMethodsInterceptorPoint[] methodsInterceptorPoints = getConstructorMethodsInterceptorPoints();

        if (null != methodsInterceptorPoints && methodsInterceptorPoints.length > 0){
            for (ConstructorMethodsInterceptorPoint methodsInterceptorPoint : methodsInterceptorPoints) {
                final String methodsInterceptor = methodsInterceptorPoint.getConstructorInterceptor();
                if (null == methodsInterceptor || methodsInterceptor.trim().equals("")){
                    log.warn("{} 增强类没有构造拦截器",typeName);
                    return builder;
                }
                // 对于构造方法进行增强
                builder = builder.constructor(methodsInterceptorPoint.getConstructorMatcher())
                        .intercept(SuperMethodCall.INSTANCE.andThen(
                                MethodDelegation.withDefaultConfiguration()
                                        .to(new ConstructorInter(methodsInterceptor,classLoader))
                        ));
            }

        }

        if (null != instanceMethodsInterceptorPoints && instanceMethodsInterceptorPoints.length > 0){
            for (InstanceMethodsInterceptorPoint instanceMethodsInterceptorPoint : instanceMethodsInterceptorPoints) {
                final String methodsInterceptor = instanceMethodsInterceptorPoint.getMethodsInterceptor();
                if (null == methodsInterceptor || methodsInterceptor.trim().equals("")){
                    log.warn("{} 增强类没有实例拦截器",typeName);
                    return builder;
                }
                ElementMatcher<MethodDescription> methodsMatcher = instanceMethodsInterceptorPoint.getMethodsMatcher();
                // 对于实例方法进行增强
                builder = builder.method(not(isStatic()).and(methodsMatcher))
                        .intercept(MethodDelegation.withDefaultConfiguration()
                                .to(new InstMethodsInter(methodsInterceptor,classLoader)));
            }
        }

        // 获取静态方法拦截器
        final StaticMethodsInterceptorPoint[] staticMethodsInterceptorPoints = getStaticMethodsInterceptorPoints();
        if (null == staticMethodsInterceptorPoints || staticMethodsInterceptorPoints.length == 0){
            return builder;
        }
        for (StaticMethodsInterceptorPoint methodsInterceptorPoint : staticMethodsInterceptorPoints) {
            final String methodsInterceptor = methodsInterceptorPoint.getMethodsInterceptor();
            if (null == methodsInterceptor || methodsInterceptor.trim().equals("")){
                log.warn("{} 增强类没有静态拦截器",typeName);
                return builder;
            }

            builder = builder.method(isStatic().and(methodsInterceptorPoint.getMethodsMatcher()))
                    .intercept(MethodDelegation.withDefaultConfiguration()
                            .to(new StaticMethodsInter(methodsInterceptor,classLoader)));
        }

        return builder;
    }

}
